package lv.solcraft.replication.server.api;

import java.util.List;

import lv.solcraft.replication.server.bdb.Database;
import lv.solcraft.replication.server.bdb.TxTemplateNoResult;
import lv.solcraft.replication.server.dao.OperDataAccess;
import lv.solcraft.replication.server.dao.OperSiteDataAccessFactory;
import lv.solcraft.replication.server.model.Oper;
import lv.solcraft.replication.server.model.OperSite;
import lv.solcraft.replication.server.model.OperState;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.sleepycat.je.Transaction;

@Service
public class SaveOpersCommand {

    private static final Logger log = Logger.getLogger(SaveOpersCommand.class);

    private final Database database;
    private OperDataAccess operDataAccess;
    private OperSiteDataAccessFactory operSiteDataAccessFactory;

    @Autowired
    public SaveOpersCommand(Database database) {
        this.database = database;
        this.operDataAccess = database.getOperDataAccess();
        this.operSiteDataAccessFactory = database.getOperSiteDataAccessFactory();
    }

    protected void save(Oper oper, List<Long> forSites) {
        try {
            oper.inject(operDataAccess, operSiteDataAccessFactory);
            if (log.isDebugEnabled()) {
                log.debug("Saving oper: " + oper.toJSON(false).toString(1));
            }
            if (!oper.persistNew()) {
                // operation already exists, do nothing
                return;
            }
            for (Long siteId : forSites) {
                if (siteId.equals(oper.getOriginSiteId())) {
                    // don't store opersite for owner site
                    continue;
                }
                OperSite operSite = oper.createOperSite(siteId, OperState.NEW);
                if (log.isDebugEnabled()) {
                    log.debug("Saving oper site: " + operSite);
                }
                try {
                    operSite.persist();
                } catch (RuntimeException e) {
                    log.error("Failed to save oper: " + oper.toJSON(false).toString(1));
                    throw e;
                }
            }
        } catch (RuntimeException e) {
            log.error("Failed to save oper: " + oper.toJSON(false).toString(1));
            throw e;
        }
    }

    public final void save(final List<Oper> opers, final List<Long> forSites) {
        for (final Oper oper : opers) {
            new TxTemplateNoResult(database, 10) {
                @Override
                protected void executeInTxNoResult(Transaction tx) throws Exception {
                    save(oper, forSites);
                }
            }.execute();
        }
    }

}
